#--*-- coding:utf-8 --*--

import sys
import os
import os.path
import platform
import shutil
from pyqt4_pyside import *
from aber import *
    
from logwidget import LogWidget

class CalcPage(QtGui.QWidget):
    def __init__(self,  parent=None):
        super(CalcPage,  self).__init__(parent)
        
        self.readSettings()
        
        hbox1 = QtGui.QHBoxLayout()
        self.filePathEdit = QtGui.QLineEdit()
        self.filePathEdit.setReadOnly(True)
        self.openPathButton = QtGui.QPushButton(u"选择文件...")
        hbox1.addWidget(self.filePathEdit)
        hbox1.addWidget(self.openPathButton)
        
        hbox2 = QtGui.QHBoxLayout()
        self.settingsApertureSizeButton = QtGui.QPushButton(u"设置光阑大小...")
        self.settingsLandEnergyButton = QtGui.QPushButton(u"设置落点能量...")
        self.startButton = QtGui.QPushButton(u"开始计算")
        self.startButton.setDisabled(True)
        hbox2.addWidget(self.settingsApertureSizeButton)
        hbox2.addWidget(self.settingsLandEnergyButton)
        hbox2.addWidget(self.startButton)
        
        self.progressBar = QtGui.QProgressBar()
        self.progressBar.setRange(0, 100)
        self.progressBar.setValue(0)
        self.logWidget = LogWidget()
        
        vbox = QtGui.QVBoxLayout(self)
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        vbox.addWidget(self.progressBar)
        vbox.addWidget(self.logWidget)
        
        self.openPathButton.clicked.connect(self.onOpenPathButtonClicked)
        self.settingsApertureSizeButton.clicked.connect(self.onSettingsApertureSize)
        self.settingsLandEnergyButton.clicked.connect(self.onSettingsLandEnergy)
        self.startButton.clicked.connect(self.onStartButtonClicked)
        #self.setStyleSheet("background-color: rgb(200, 85, 0);")

    def onOpenPathButtonClicked(self):
        path = QtGui.QFileDialog.getOpenFileName(self,  u"选择aber的数据文件",  "",  "aber data(*.dat)")
        if isinstance(path,  tuple): #pyside return a tuple
            path = path[0]
        if path:
            self.filePathEdit.setText(path)
            self.startButton.setEnabled(True)
            
            self.updateCalcInfo()
            
            self.logWidget.addLogString(u"<br/>")
            self.logWidget.addLogString(u"选择文件：{}".format(path))    
            self.aberDatInfo(path)
            
            self.logWidget.addLogString(u"光阑大小：{}".format(' '.join(self.apertureSizeList) if self.apertureSizeList else "None"))
            self.logWidget.addLogString(u"落点能量：{}".format(' '.join(self.landEnergyList) if self.landEnergyList else "None"))
            self.logWidget.addLogString(u"需进行 {} 次ABER计算\n".format(self.calc_count))

        
    def aberDatInfo(self,  path):
        d = AberDatFile(path)
        dir = os.path.dirname(path)
        fs = d.getDependFileNames()
        self.logWidget.addLogString(u"依赖文件：{}".format(fs))
        for s in fs:
            if (os.path.exists(os.path.join(dir, s))):
                self.logWidget.addLogString(u"{}：找到".format(s))
            else:
                self.logWidget.addLogString(u"{}：未找到".format(s))
            
        
    def updateCalcInfo(self):
        len1 = len(self.apertureSizeList) if self.apertureSizeList else 1
        len2 = len(self.landEnergyList) if self.landEnergyList else 1
        
        self.calc_count = len1 * len2
        self.progressBar.setRange(0,  self.calc_count)
        self.progressBar.setValue(0)
        
    def onSettingsApertureSize(self):
        dlg = ListSettingsDialog(u"设置光阑大小",  self.apertureSizeList)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.apertureSizeList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"光阑大小：{}".format(' '.join(self.apertureSizeList) if self.apertureSizeList else "None"))
        
    def onSettingsLandEnergy(self):
        dlg = ListSettingsDialog(u"设置落点能量",  self.landEnergyList)
        if dlg.exec_() == QtGui.QDialog.Accepted:
            self.landEnergyList = dlg.dataList()
            self.updateCalcInfo()
            self.logWidget.addLogString(u"落点能量：{}".format(' '.join(self.landEnergyList) if self.landEnergyList else "None"))
    
        
    def onStartButtonClicked(self):
        rootaberfilePath = self.filePathEdit.text()
        if (not (self.landEnergyList and self.apertureSizeList)): #note
            return
        try:
            act = self.calcThread.isActive()
        except:
            pass
        else:
            if act:
                return
        self.calcThread = CalcThread(rootaberfilePath,  self.apertureSizeList, self.landEnergyList)
        self.calcThread.calccount.connect(self.progressBar.setValue)
        self.calcThread.logdata.connect(self.logWidget.addLogString)
        self.calcThread.start()
        
    def readSettings(self):
        settings = QtCore.QSettings()
        settings.beginGroup("calc")
        self.apertureSizeList = settings.value("aperturesizelist",  None)
        self.landEnergyList = settings.value("landenergylist",  None)
        settings.endGroup()
        
    def writeSettings(self):
        settings=QtCore.QSettings()
        settings.beginGroup("calc")
        settings.setValue("aperturesizelist",  self.apertureSizeList)
        settings.setValue("landenergylist",  self.landEnergyList)
        settings.endGroup()
        
class CalcThread(QtCore.QThread):
    logdata = QtCore.Signal(unicode)
    calccount = QtCore.Signal(int)
    def __init__(self,  rootFile,  aperture, landenergy,  parent=None):
        super(CalcThread,  self).__init__(parent)
        self.rootAberFile = rootFile
        self.apertureSizeList = aperture
        self.landEnergyList = landenergy
        self.updateCalcInfo()
        
    def updateCalcInfo(self):
        len1 = len(self.apertureSizeList) if self.apertureSizeList else 1
        len2 = len(self.landEnergyList) if self.landEnergyList else 1
        self.calc_count = len1 * len2
        
        self.aberfilename = os.path.basename(self.rootAberFile)
        aberdir = os.path.dirname(self.rootAberFile)
        self.calcrootdir = self.rootAberFile[:-4]  #remove .dat
        print self.calcrootdir
        if not os.path.exists(self.calcrootdir):
            os.mkdir(self.calcrootdir)
            
        self.aberDatFile = AberDatFile(self.rootAberFile)
        self.dependedFiles = self.aberDatFile.getDependFileNames()
        for f in self.dependedFiles:
            if f.endswith('.axv'):
                self.axvfilename = f
        os.chdir(self.calcrootdir)
        
    def run(self):
        self.logdata.emit(os.environ['PATH'].decode(sys.getfilesystemencoding( )))
        calc_count = 0
        res_data = []
        for aperture in self.apertureSizeList:
            ap_dir = u"光阑大小{}".format(aperture)
            self.logdata.emit(u"  当前光阑大小：{}".format(aperture))
            if not os.path.exists(ap_dir):
                os.mkdir(ap_dir)
            os.chdir(ap_dir)
            self.aberDatFile.setRealApertureDiameter(aperture)
            res_data.append([])
            for landenergy in self.landEnergyList:
                le_dir = u"落点能量{}".format(landenergy)
                self.logdata.emit(u"    当前落点能量：{}".format(landenergy))
                if not os.path.exists(le_dir):
                    os.mkdir(le_dir)
                os.chdir(le_dir)
                le = float(landenergy)
                volts = (le+8000,  le,  le)
                self.aberDatFile.setELensVoltsAndName(volts, self.axvfilename)
                self.aberDatFile.save(self.aberfilename)
                for f in self.dependedFiles:
                    try:
                        shutil.copyfile(os.path.abspath("../../../%s" % f), f)
                    except:
                        shutil.copyfile(os.path.abspath("../../%s" % f), f)
                ret = callMunroAber(self.aberfilename)
                self.logdata.emit(u"    aber结果：{}".format(ret))
                
                resFile = AberResFile(self.aberfilename[:-4]+".res")
                v1 = resFile.getMLensExcitation()
                v2 = resFile.getBeamSpotDiameter()
                v3 = resFile.getDeflectionSensitivities()
                res_data[-1].append((v1, v2, v3))
                os.chdir("..")  #landenergy
                calc_count += 1
                self.calccount.emit(calc_count)
            os.chdir("..")  # aperture
        self.writeResult(res_data)
        
    def writeResult(self, data):
        self.writeOneResult(data,  0,  u"激励.txt")
        self.writeOneResult(data, 1,  u"束班.txt")
        self.writeOneResult(data, 2,  u"偏转灵敏度.txt")
        
    def writeOneResult(self, data,  index,  filename):
        file_data = []
        # 落点能量为第一行， 每行 对应不同光阑大小
        line_items = ["%15s" % "aperture"]
        for le in self.landEnergyList:
            line_items.append("%15s" % le)
        line_items.append('\n')
        file_data.append(' '.join(line_items)) # header line
        for row in range(len(self.apertureSizeList)):
            line_items = ["%15s" % self.apertureSizeList[row]]
            for col in range(len(self.landEnergyList)):
                line_items.append("%15s" % data[row][col][index])
            line_items.append('\n')
            file_data.append(' '.join(line_items))
            
        with open(filename, 'w') as f:
            f.writelines(file_data)
            self.logdata.emit(u"提取文件：{}".format(filename))
        
class ListSettingsDialog(QtGui.QDialog):
    def __init__(self, title="",  dataList=None,  parent=None):
        super(ListSettingsDialog, self).__init__(parent)
        self.setWindowTitle(title)
        
        groupBox1 = QtGui.QGroupBox(u"添加范围(开始、结束、步长)")
        hbox1 = QtGui.QHBoxLayout(groupBox1)
        self.startValueEdit = self.createSpinBox(0,  1000)
        self.endValueEdit = self.createSpinBox(0,  322000)
        self.stepValueEdit = self.createSpinBox(0.001,  10000)
        self.addRangeValueButton = QtGui.QPushButton(u"添加")
        hbox1.addWidget(self.startValueEdit)
        hbox1.addWidget(self.endValueEdit)
        hbox1.addWidget(self.stepValueEdit)
        hbox1.addWidget(self.addRangeValueButton)
        
        groupBox2 = QtGui.QGroupBox(u"添加单个值")
        hbox2 = QtGui.QHBoxLayout(groupBox2)
        self.singleValueEdit = self.createSpinBox(0,  10000)
        self.addSingleValueButton = QtGui.QPushButton(u"添加")
        hbox2.addWidget(self.singleValueEdit)
        hbox2.addWidget(self.addSingleValueButton)
        
        hbbox = QtGui.QHBoxLayout()
        self.okButton = QtGui.QPushButton(u"确定")
        self.clearButton = QtGui.QPushButton(u"清除")
        hbbox.addWidget(self.clearButton)
        hbbox.addStretch(0)
        hbbox.addWidget(self.okButton)
        
        self.listView = QtGui.QListView()
        vbox = QtGui.QVBoxLayout(self)
        vbox.addWidget(groupBox1)
        vbox.addWidget(groupBox2)
        vbox.addWidget(self.listView)
        vbox.addLayout(hbbox)
        
        self._dataList = dataList if dataList else []
        self.listModel = QtGui.QStringListModel(self._dataList);
        self.listView.setModel(self.listModel)
        
        self.addRangeValueButton.clicked.connect(self.onAddRangeButtonClicked)
        self.addSingleValueButton.clicked.connect(self.onAddSingleButtonClicked)
        self.clearButton.clicked.connect(self.onClearButtonClicked)
        self.okButton.clicked.connect(self.onOkButtonClicked)
        
    def onAddRangeButtonClicked(self):
        start = self.startValueEdit.value()
        end = self.endValueEdit.value()
        step = self.stepValueEdit.value()
        if (start > end):
            return
            
        while (start <= end):
            row = self.listModel.rowCount()
            self.listModel.insertRows(row,  1)
            self.listModel.setData(self.listModel.index(row),  str(start))
            start += step
        
        
    def onAddSingleButtonClicked(self):
        row = self.listModel.rowCount()
        self.listModel.insertRows(row,  1)
        self.listModel.setData(self.listModel.index(row),  str(self.singleValueEdit.value()))
        
    def onClearButtonClicked(self):
        self.listModel.setStringList([])
        
    def onOkButtonClicked(self):
        self.done(QtGui.QDialog.Accepted)
        
    def createSpinBox(self,  minimum,  maximum):
        edit = QtGui.QDoubleSpinBox()
        edit.setRange(minimum,  maximum)
        edit.setDecimals(3)
        return edit
    
    def dataList(self):
        return self.listModel.stringList()
